﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using MingYuanYun.StructuredLog.Abstractions;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace MingYuanYun.WebApi.Logging
{
    public class RequestLogMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly RequestLogOptions _options;

        public RequestLogMiddleware(RequestDelegate next, IOptions<RequestLogOptions> options)
        {
            this._next = next;
            this._options = options?.Value ?? new RequestLogOptions();
        }

        public async Task Invoke(HttpContext context, IMyLogger logger)
        {
            if (_options.ExcludeUrls.Any(x => context.Request.Path.Value.IndexOf(x, StringComparison.OrdinalIgnoreCase) >= 0))
            {
                await _next(context);
            }
            else
            {
                using (var requestBodyStream = new MemoryStream())
                {
                    var originalRequestBody = context.Request.Body;

                    await context.Request.Body.CopyToAsync(requestBodyStream);
                    requestBodyStream.Seek(0, SeekOrigin.Begin);

                    var requestBodyText = await new StreamReader(requestBodyStream).ReadToEndAsync();

                    requestBodyStream.Seek(0, SeekOrigin.Begin);
                    context.Request.Body = requestBodyStream;

                    var watch = Stopwatch.StartNew();

                    await _next(context);

                    watch.Stop();

                    context.Request.Body = originalRequestBody;

                    var logData = new
                    {
                        RequestPath = context.Request.Path,
                        QueryString = context.Request.QueryString.ToString(),
                        RequestBody = requestBodyText,
                        DateTime = DateTime.Now,
                        Timeconsuming = watch.ElapsedMilliseconds
                    };

                    logger.Info(logData);
                }
            }
        }
    }
}
